#include "fxcc/core/graph/opengl3/Texture2DJack.h"
#include "fxcc/core/graph/opengl3/RenderStates.h"
#include "fxcc/core/graph/opengl3/gliUtils2.h"
#include "fxcc/core/cmdUtils.h"

#include "stb_image.h"
#include "stb_image_write.h"

using namespace fxcc::graph;
using namespace fxcc::graph::opengl3;

Texture2DJack::Texture2DJack(const common::Texture2DJack::Desc& desc)
	:common::Texture2DJack(desc), fxcc::graph::opengl3::Texture(GL_TEXTURE_2D)
{
	Load();
}

void Texture2DJack::Load()
{
	this->m_Available = Init();
}

bool Texture2DJack::Init()
{

	switch (m_Desc.m_Type)
	{
	case Desc::Type::_WIC_:
		return InitWIC();
	case Desc::Type::_DDS_:
		return InitDDS();
	case Desc::Type::_AllOC_:
		return InitAlloc();
	default:
		break;
	}
	return true;

}

void Texture2DJack::SetShader(int index) const
{
	Active(index);
}

bool Texture2DJack::InitDDS()
{
	Delete();
	m_Id = gliUtils2::create_texture(m_Desc.m_DDSPath.c_str());

	if (m_Id)
	{
		gli::texture texture=gli::load(m_Desc.m_DDSPath);
		auto Extent0 = texture.extent(0);
		auto fmt = texture.format();

		m_Desc.m_MipmapData.m_Width = Extent0.x;
		m_Desc.m_MipmapData.m_Height = Extent0.y;
		m_Desc.m_MipmapData.m_NrComponent = gli::component_count(fmt);
		m_Desc.m_MipmapData.m_HDR= gli::is_float(fmt);
		m_Desc.m_MipmapData.m_Mipmaps = texture.levels();

		Bind();
		SetSampler(m_Desc.m_SampleType);
		UnBind();
	}

	return true;
}

bool Texture2DJack::InitWIC()
{
	auto m_ImageMipMap = std::make_shared<fxcc::graph::common::ImageMipmap>(m_Desc.m_WICConfig);
	if (!m_ImageMipMap->m_Available)
	{
		return false;
	}

	Create();
	Bind();
	TexImage2D(m_Target, 0, m_ImageMipMap->m_WICTexture);
	SetSampler(m_Desc.m_SampleType);
	UnBind();

	m_Desc.m_MipmapData = m_ImageMipMap->m_WICTexture;
	return true;
}

bool fxcc::graph::opengl3::Texture2DJack::InitAlloc()
{
	
	Create();
	Bind();
	TexImage2D(m_Target, 0, m_Desc.m_MipmapData);
	SetSampler(m_Desc.m_SampleType);
	UnBind();
	return true;


}

std::string fxcc::graph::opengl3::Texture2DJack::SaveAsHDR(const std::string& hdrPath, int level) const
{
	int hdr = m_Desc.m_MipmapData.m_HDR;

	if (hdr)
	{
		auto imageData = GetImage2D(this->m_Target, level, m_Desc.m_MipmapData.m_NrComponent, m_Desc.m_MipmapData.m_HDR);;
		imageData.SaveHDR(hdrPath);
	}
	else
	{

		ztclog::info("not hdr failed save hdr");
	}

	return hdrPath;
}

std::string fxcc::graph::opengl3::Texture2DJack::SaveAsBMP(const std::string& bmpPath, int level) const
{
	int hdr = m_Desc.m_MipmapData.m_HDR;
	if (hdr)
	{
		ztclog::info("this is hdr failed save hdr");
	}
	else
	{
		auto imageData = GetImage2D(this->m_Target, level, m_Desc.m_MipmapData.m_NrComponent, m_Desc.m_MipmapData.m_HDR);;
		imageData.SaveBMP(bmpPath);
	}

	return bmpPath;
};

std::string fxcc::graph::opengl3::Texture2DJack::SaveImage(const std::string& nameNoSuffix,  int level) const
{
	assert(m_Desc.m_MipmapData.Size() && "Mipmap has a zero properties");

	fxcc::graph::common::ImageMipmap::MipMapData imageData;
	bool flag = LoadImage(imageData, GetTarget(), level, m_Desc.m_MipmapData.m_NrComponent, m_Desc.m_MipmapData.m_HDR);
	std::string realPath = imageData.SaveImage(nameNoSuffix);
	return realPath;
}

bool fxcc::graph::opengl3::Texture2DJack::SimpleSaveDDS(const std::string& ddsPath)
{
	std::string originPath = SaveImage("nameNoSuffix");

	glm::ivec2 sz;
	sz.x = m_Desc.m_MipmapData.m_Width;
	sz.y = m_Desc.m_MipmapData.m_Height;
	cmdUtils::CreateDDSFromImage(originPath, ddsPath, sz);

	if(fs::exists(originPath))
	{
		fs::remove(originPath);
	}
	return fs::exists(ddsPath);


}

bool fxcc::graph::opengl3::Texture2DJack::CreateDDSMipmapFromLevel0(const std::string& ddsPath, int levels, bool generateMipmap)
{

	int level = 0;

	auto imageData = m_Desc.m_MipmapData;

	auto fmt = gliUtils::GetFormat(imageData.m_NrComponent, imageData.m_HDR);

	gli::texture2d texture(fmt, gli::extent2d(imageData.m_Width, imageData.m_Height), levels);
	LoadImage(imageData, GetTarget(), level, imageData.m_NrComponent, imageData.m_HDR);

	std::size_t expectedSize = texture.size(level);
	assert(imageData.DataSize() == expectedSize);
	memcpy(texture.data(0, 0, level), imageData.GetData(), imageData.DataSize());

	if (generateMipmap)
	{
		gli::filter filter1 = gli::filter::FILTER_LINEAR;
		gli::generate_mipmaps(texture, filter1);
	}

	gli::save_dds(texture, ddsPath);

	return fs::exists(ddsPath);
}

bool fxcc::graph::opengl3::Texture2DJack::CreateDDSMipmap(const std::string& ddsPath)
{
	auto imageData = m_Desc.m_MipmapData;

	auto fmt = gliUtils::GetFormat(imageData.m_NrComponent, imageData.m_HDR);

	gli::texture2d texture(fmt, gli::extent2d(imageData.m_Width, imageData.m_Height), imageData.m_Mipmaps);

	for (int level = 0; level < imageData.m_Mipmaps; level++)
	{
		LoadImage(imageData, GetTarget(), level, imageData.m_NrComponent, imageData.m_HDR);
		std::size_t expectedSize = texture.size(level);
		assert(imageData.DataSize() == expectedSize);
		memcpy(texture.data(0, 0, level), imageData.GetData(), imageData.DataSize());
	}

	gli::save_dds(texture, ddsPath);

	return fs::exists(ddsPath);
}

